// ==UserScript==
// @name        明日方舟公开招募
// @namespace   https://github.com/lzghzr/TampermonkeyJS
// @version     0.0.1
// @author      lzghzr
// @description 为Wiki添加OCR
// @supportURL  https://github.com/lzghzr/TampermonkeyJS/issues
// @match       https://prts.wiki/w/%E5%B9%B2%E5%91%98%E4%B8%80%E8%A7%88
// @license     MIT
// @grant       none
// @run-at      document-end
// ==/UserScript==

const Fingerprints: { [index: number]: { [index: string]: string } } = {
  '2': {
    '爆发': '0101111001010100011111100111010001111110111101000111001011111110111111101111111011111110001000001111111000111100011111100011110001111110011001001111111001111100111111101101100011111100110110001011111010111100101110100110011000001000000000000000000000000000',
    '防护': '0000100011001000111010001100100011111110110011001111111111111110110110001111011011011000111100101101111011111110111111101111111010110111111101101111011011110000111101101111000010110110111000001011011011100000101011001110000000001100000000000000000000000000',
    '减速': '0000011000001000100001101011111010111110111111101111111001001000111001000011111000111110111011100010011011111110001111100111111001111110010111001111110001111100111111000111111011111110111010001100111011110110010011101011111000000000000000000000000000000000',
    '控场': '0100110001000000010011000111110001011111010011001111001101001100111111011111100001011110010111100101001001011110011100000101111011111110010111101100110001111110010011001111101001001100110010100111111100011010111111110001011000000000000000000000000000000000',
    '群攻': '0000101000001000011110100000100001111010111110001111111111111110111111100101111001010100010101100111111001111110010011100111110001110100010011001111111101101100110111111110110001010100100111000111010000111110011101000011001000000100000000000000000000000000',
    '生存': '0101000000100000010100000010000001010000111111100111111011111110111111100110000011010000010111001001000001011100000100001100110001111110110010000001000011111110000100000111111000010000010010001111111001001000111111100101100000000000010110000000000000000000',
    '输出': '0100100000010000110011001001010011111100110101001111011011010100111111101101010011000000111111001111111011111100111111100001000001011110100101100111111010010110111111101001011011011110100101100101101011111110010111101111111000000000000000000000000000000000',
    '位移': '0110100001001000011010001111110001001000110111100111111001110100110000001111110011010100111110001101010011111100010101001100111001010100111111100101010011111110010101011110110001010100010011000111111001011000011111100111000000000000010000000000000000000000',
    '新手': '0100001000001100011011101111110011111100111100001110100000010000011010001111110011111110111111101111111000010000011011100001000011111110111111100110111011111110111011100001000011111110000100001101011000010000010101100111000000000100011000000000000000000000',
    '削弱': '0110001011101110111100101111111011111010001001101111101011101110111110101111111011111010100110001001101011111110111110101111111010011010101110101111101011101110111110100110111010010010111111101001001010110110101101100110110000000100000000000000000000000000',
    '召唤': '0000000000010000111111100001110011111110110111000011011011110100001001101111111001100110111111100110110011111110110011001111111001111110111111100111111011111110010001101101100001000110100111000111111010110110011111100011011001000100001000000000000000000000',
    '支援': '0001000010000100000100001011110011111110101011001111111111101100000100011111111000010000101111101111110010111110111111001111111001101101110111000110110111011100001110001011010000111000101111000111110010101100111011101111111010000010100100100000000000000000',
    '治疗': '0000100000010000110110000001100001110100011111100001010011111110001101101100000011111110111111101111111011111110000000000100110000111110110010000111111011001000011100100100100001110010110010001111111010001000101111101001100000100010000110000000000000000000',
  },
  '3': {
    '近战位': '0100011001001100010111100100111001010000011011100101000001111100000111110110111011011111010011101101010001100110010101001111011001010100111101100101010010010110011101001001010001110100100111111111111111111110101111111001111000000000000000000000000000000000',
    '远程位': '0000000001000000101111101101111011111110110101100100000001010110001111101101111011111110111111111101010011011111010101001111111001010100111010000101011011111100011101111101111001100110010010001110000001001000101111100111111000001000010000000000000000000000',
  },
  '4': {
    '费用回复': '0011100000000000011111100111111000111010011111100111111001010010011110000101111001111110011111100110101001010110111010100101001011111100011111100101010011111110010101001101001001011100110100100111111010010110111001101001111000000000000000000000000000000000',
    '辅助': '0100011000001000010001101110100011111110111010001111111010101100110011001111111011111110111010101111011010101010111111101110101101111110111010100111011010101010111111101011101011111110111110100111011011010110011101100011111000010110000001000000000000000000',
    '近卫': '0000011000000000110111101111111001011000111111100101000000110110000100000011011000011110001101101101010000110110010101000011011001010100001111000111010000111100011101000011000001100100001100001111001011111110101111101111111000000000000000000000000000000000',
    '狙击': '0000000000010000111111100001000001111110011111100101001011111110111100100001000010111110000100000111011011111110011100101111111001111110000100001111111001010110101100100101011000110010010101100111111001111110011111110111111001000000000001000000000000000000',
    '快速复活': '0100100000001000010010001011111001011110111111101111111001001000111010100011111011101010111011101100101011111110011111100111111001111110010111000100110001011100010111000111111001011110111010000111011011110110011100101011111100000000000000000000000000000000',
    '术师': '0001100001100000000111000111111000011110111111100001100011101000111111101111111011111110111111100001100011111010001111001111101000111100111110100111111011111010011111100101101011011011010111101001101001011000000110001100100000010000000010000000000000000000',
    '特种': '0000010000000000010001001110110011011110111011001111111001011110111001000101111011111110111111101101111001011110010001100111111001111110111111101111111011111110110111101101111001001110110011000100001001001100010001100100110001000100010011000000000000000000',
    '先锋': '0001000010001000011100001101100001111110111111000111111010111100010100001011110011010000111111000001000001111110111111100111101000101000111111100010100001001000001010000101111001101010011011000110101001111110110011101100100010000110000010000000000000000000',
    '医疗': '0000000000010000111111100001000011111110111111101010000111111110111111011100000011111100111111001001000011111101111111101100110111111111110110001001100111011000101111001001100011100100100110001111111010011000111111111011100000000000001100000000000000000000',
    '支援机械': '0001000001000000000100000111111000011000011110101111111011011110000110001111111000010000011111100111111001011000011111100111111001100100111110000010110011011110001111000101111000011000011111000011110001111100111011101111111011000010111100100000000000000000',
    '重装': '0000110001001000011111001100100000010000111111101111111001111110000100000100100001111110110111100101011011011110011111100101000001010110111111100111111011111110011111100111111001111110111011000001000011111100111111100111011000000000010000000000000000000000',
    '资深干员': '0001000000000000010111101111111001111110011111100011101000110110011011000001010011111110111101101111001011101010011111000001100001111110001111100101011001011100010101100101110001011110111111100011111010101110111001101010100011000000000000000000000000000000',
  },
  '6': {
    '高级资深干员': '0001000001000000000100001111110011111110111111000000000010010100011111001101110001000101110111110111110111011111000000001101011011111110110111001011001111011100111110100111110011101010111111001111101111111100101001101011111110000100000000010000000000000000',
  }
}

const filter = document.querySelector<HTMLDivElement>('#filter-wrapper')

const input = document.createElement('input')
input.type = 'file'
input.accept = 'image/*'

if (filter !== null) filter.insertBefore(input, <Element>filter.firstElementChild)
else document.body.appendChild(input)

window.addEventListener('paste', e => {
  e.preventDefault()
  input.files = (<ClipboardEvent>e).clipboardData?.files || null
  onChange()
})

input.addEventListener('change', () => onChange())

function onChange() {
  // 清空选择
  const calc = document.querySelector<HTMLInputElement>(`#filter-wrapper input[data-f="calc"]`)
  calc?.click()
  const selectFilter = document.querySelectorAll<HTMLInputElement>(`#filter-wrapper button.iF-select-none`)
  selectFilter.forEach(button => button.click())

  const canvas = document.createElement('canvas')
  const ctx = <CanvasRenderingContext2D>canvas.getContext('2d')
  const file = (<FileList>input.files)[0]
  const img = document.createElement('img')
  img.addEventListener('load', () => {
    const fontSize = 31
    // 固定参数
    const dx = 540
    const dy = 530
    const dw = 760 / 2
    const dh = 220
    // 原图比例
    const w_h = 1920 / 1080
    canvas.width = dw
    canvas.height = dh
    // 裁切+缩放
    if (img.width / img.height >= w_h) {
      const scaling = img.height / 1080
      const width = img.height * w_h
      const sx = Math.round((img.width - width) / 2 + dx * scaling)
      const sy = Math.round(dy * scaling)
      const sw = Math.round(dw * 2 * scaling)
      const sh = Math.round(dh * scaling)
      ctx.drawImage(img, sx, sy, sw, sh, 0, 0, dw, dh)
    }
    else {
      const scaling = img.width / 1920
      const height = img.width / w_h
      const sx = Math.round(dx * scaling)
      const sy = Math.round((img.height - height) / 2 + dy * scaling)
      const sw = Math.round(dw * 2 * scaling)
      const sh = Math.round(dh * scaling)
      ctx.drawImage(img, sx, sy, sw, sh, 0, 0, dw, dh)
    }
    const imageData = ctx.getImageData(0, 0, dw, dh)
    const imagePixels = imageData.data
    // 创建二维数组
    const vertical: number[][] = Array(dw)
    for (let i = 0; i < dw; i++) vertical[i] = Array(dh)
    const horizontal: number[][] = Array(dh)
    for (let i = 0; i < dh; i++)  horizontal[i] = Array(dw)
    // 二值化
    for (let i = 0; i < imagePixels.length; i += 4) {
      const avg = imagePixels[i] < 80 ? 0 : 255
      vertical[i / 4 % dw][Math.floor(i / 4 / dw)] = avg === 0 ? 0 : 1
      horizontal[Math.floor(i / 4 / dw)][i / 4 % dw] = avg === 0 ? 0 : 1
    }
    // 查找行
    const Y: number[] = []
    for (let row = 0; row < horizontal.length; row++) {
      const blackPixel = sumBlackPixel(horizontal[row])
      if (blackPixel > 80 && Y.length % 2 === 0) {
        Y.push(row + 2)
        row += 52
      }
      if (blackPixel < 80 && Y.length % 2 === 1) {
        Y.push(row - 3)
        row += 32
      }
    }
    // 查找列
    const X: number[] = []
    for (let col = 0; col < vertical.length; col++) {
      const blackPixel = sumBlackPixel(vertical[col])
      if (blackPixel > 40 && X.length % 2 === 0) {
        X.push(col + 2)
        col += 60
      }
      if (blackPixel < 40 && X.length % 2 === 1) {
        X.push(col - 3)
        col += 8
      }
    }
    // 是否获取到正确的tag数
    if (X.length === 6 && Y.length === 4)
      for (let i = 0; i < 5; i++) {
        const tagsx = X[(i % 3) * 2]
        const tagsy = Y[Math.floor(i / 3) * 2]
        const tagsw = X[(i % 3) * 2 + 1] - X[(i % 3) * 2] + 1
        const tagsh = Y[Math.floor(i / 3) * 2 + 1] - Y[Math.floor(i / 3) * 2] + 1

        const tagImageData = ctx.getImageData(tagsx, tagsy, tagsw, tagsh)
        const tagPixels = tagImageData.data
        // 创建二维数组
        const vertical: number[][] = Array(tagsw)
        for (let i = 0; i < tagsw; i++) vertical[i] = Array(tagsh)
        const horizontal: number[][] = Array(tagsh)
        for (let i = 0; i < tagsh; i++)  horizontal[i] = Array(tagsw)
        // 二值化
        for (let i = 0; i < tagPixels.length; i += 4) {
          const avg = tagPixels[i] < 80 ? 0 : 255
          vertical[i / 4 % tagsw][Math.floor(i / 4 / tagsw)] = avg === 0 ? 0 : 1
          horizontal[Math.floor(i / 4 / tagsw)][i / 4 % tagsw] = avg === 0 ? 0 : 1
        }
        // 获取文本行
        let textY: number = -1
        let limitedY = horizontal.length
        for (let row = 8; row < horizontal.length; row++) {
          if (limitedY <= 0) break
          const blackPixel = sumBlackPixel(horizontal[row])
          if (textY === -1 && blackPixel < tagsw - 8) {
            textY = 0
            row -= 2
          }
          else if (textY === 0 && blackPixel < tagsw)
            row -= 2
          else if (textY === 0 && blackPixel === tagsw) {
            textY = row + 1
            break
          }
          limitedY--
        }
        // 获取文本列
        let textX: number = -1
        let limitedX = vertical.length
        let lengthX = 0
        for (let col = 8; col < vertical.length; col++) {
          if (limitedX <= 0) break
          const blackPixel = sumBlackPixel(vertical[col])
          if (textX === -1 && blackPixel < tagsh - 8) {
            textX = 0
            col -= 2
          }
          else if (textX === 0 && blackPixel < tagsh)
            col -= 2
          else if (textX === 0 && blackPixel === tagsh) {
            lengthX = Math.round((tagsw - col * 2) / (fontSize / 2))
            textX = col + 1
            break
          }
          limitedX--
        }
        // tag字数
        if (Fingerprints[lengthX] !== undefined) {
          const txtdw = 32
          const txtdh = 32

          const txtImageData = ctx.getImageData(tagsx + textX, tagsy + textY, txtdw, txtdh)
          const txtPixels = txtImageData.data

          // 二值化并压缩
          const txtHorizontal: number[][] = Array(txtdh)
          for (let i = 0; i < txtdh; i++)  txtHorizontal[i] = Array(txtdw)
          const bin: number[] = []
          for (let i = 0; i < txtPixels.length; i += 4)
            txtHorizontal[Math.floor(i / 4 / txtdw)][i / 4 % txtdw] = txtPixels[i] < 160 ? 0 : 1
          for (let row = 0; row < txtHorizontal.length; row += 2)
            for (let col = 0; col < txtHorizontal[row].length; col += 2)
              bin.push(txtHorizontal[row][col] + txtHorizontal[row][col + 1] + txtHorizontal[row + 1][col] + txtHorizontal[row + 1][col + 1] === 0 ? 0 : 1)

          const fingerprint = bin.join('')

          const fingerprints = Fingerprints[lengthX]

          const values = Object.values(fingerprints)
          const keys = Object.keys(fingerprints)

          const arrBin = values.map(value => hammingDistance(value, fingerprint))
          const tag = keys[arrBin.indexOf(Math.min(...arrBin))]

          const tagFilter = document.querySelector<HTMLInputElement>(`#filter-wrapper input[data-f="${tag}"]`)
          if (tagFilter !== null) tagFilter.click()
        }
        else console.error('文本分割错误', textX, textY, lengthX)
      }
    else console.error('词条分割错误', X, Y)
  })
  img.src = URL.createObjectURL(file)
}

function sumBlackPixel(pixels: number[]): number {
  return pixels.reduce((p, c) => c === 0 ? p + 1 : p, 0)
}

function hammingDistance(str1: string, str2: string) {
  let distance = 0
  const str1Arr = str1.split('')
  const str2Arr = str2.split('')
  str1Arr.forEach((letter, index) => {
    if (letter !== str2Arr[index])
      distance++
  })
  return distance
}
